/***************************************************************************
 * Copyright (C) 2008 Global Biodiversity Information Facility Secretariat.  
 * All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 ***************************************************************************/
package org.gbif.metadata.webapp.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.ServletContext;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.util.ServletContextAware;
import org.appfuse.webapp.action.BaseAction;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.io.SAXReader;
import org.gbif.metadata.eml.Eml;
import org.gbif.metadata.io.MetadataFileUtils;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IUnmarshallingContext;

/**
 * An action for importing documents into the editor for modification.
 * 
 * @author dmartin
 */
public class ImportDocumentAction extends BaseAction implements ServletContextAware {

	protected String fileUrl;

	protected String documentBody;

	protected String requiredNamespace = "eml://ecoinformatics.org/eml-2.0.1";

	protected String requiredNamespacePrefix = "eml";

	protected ServletContext context;

	/**
	 * Import an EML document, retrieving via HTTP, writing the file to the
	 * local file system. Then using JIBX to parse and bind to Java model.
	 * 
	 * @return
	 */
	public String importDocument() {

		File file = null;

		if (StringUtils.isNotBlank(this.fileUrl)) {
			log.debug("Importing via url:"+this.fileUrl);
			HttpClient client = new HttpClient();
			GetMethod getMethod = new GetMethod(this.fileUrl);
			try {
				int responseCode = client.executeMethod(getMethod);
				log.debug("Response code: " + responseCode);
				InputStream input = getMethod.getResponseBodyAsStream();
				file = outputToFile(input);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				return ERROR;
			}
		} else if (StringUtils.isNotBlank(this.documentBody)) {
			log.debug("Importing pasted document");
			String docId = Long.toString(System.currentTimeMillis());
			try {
				file = MetadataFileUtils.getNewFile(context, docId);
				FileOutputStream out = new FileOutputStream(file);
				out.write(this.documentBody.getBytes());
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				return ERROR;
			}

		} else {
			//no input supplied
			return INPUT;
		}

		checkNamespaces(file);

		// dom4j parse it
		try{
			IBindingFactory bfact = BindingDirectory.getFactory(Eml.class);
			IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
			Eml eml = (Eml) uctx.unmarshalDocument(new FileInputStream(file), null);
			getRequest().getSession().setAttribute("currentDoc", file);
			getRequest().getSession().setAttribute("eml", eml);
		} catch(Exception e){
			log.error(e.getMessage(), e);
			return ERROR;
		}
		return SUCCESS;

	}

	/**
	 * Check the namespace of the supplied file, adding the mandatory
	 * eml namespace if required.
	 * 
	 * @param file
	 */
	private void checkNamespaces(File file) {
		
		SAXReader reader = new SAXReader();
		org.dom4j.Document document;
		try {
			document = reader.read(new FileInputStream(file));
			Namespace namespace = document.getRootElement().getNamespace();
			if (namespace == null
					|| (StringUtils.isBlank(namespace.getPrefix()) && StringUtils
							.isBlank(namespace.getURI()))) {

				Element element = document.getRootElement();
				element.setName("eml:eml");
				document.getRootElement().addNamespace(requiredNamespacePrefix,
						requiredNamespace);

				log.debug("Adding namespaces to document");
				file.delete();
				file.createNewFile();
				OutputStream outputStream = FileUtils.openOutputStream(file);
				outputStream.write(document.asXML().getBytes());
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}

	/**
	 * Output to local file system.
	 * 
	 * @param input
	 * @return
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private File outputToFile(InputStream input) throws Exception {

		String docId = Long.toString(System.currentTimeMillis());
		File currentDoc = MetadataFileUtils.getNewFile(context, docId);
		FileOutputStream output = new FileOutputStream(currentDoc);

		byte[] buf = new byte[1024];
		int len;
		while ((len = input.read(buf)) > 0) {
			output.write(buf, 0, len);
		}
		output.flush();
		return currentDoc;
	}

	/**
	 * @see org.apache.struts2.util.ServletContextAware#setServletContext(javax.servlet.ServletContext)
	 */
	public void setServletContext(ServletContext context) {
		this.context = context;
	}

	/**
	 * @return the fileUrl
	 */
	public String getFileUrl() {
		return fileUrl;
	}

	/**
	 * @param fileUrl
	 *            the fileUrl to set
	 */
	public void setFileUrl(String fileUrl) {
		this.fileUrl = fileUrl;
	}

	public String getDocumentBody() {
		return documentBody;
	}

	public void setDocumentBody(String documentBody) {
		this.documentBody = documentBody;
	}

	public String getRequiredNamespace() {
		return requiredNamespace;
	}

	public void setRequiredNamespace(String requiredNamespace) {
		this.requiredNamespace = requiredNamespace;
	}

	public String getRequiredNamespacePrefix() {
		return requiredNamespacePrefix;
	}

	public void setRequiredNamespacePrefix(String requiredNamespacePrefix) {
		this.requiredNamespacePrefix = requiredNamespacePrefix;
	}
}